package com.lonni.rpc.core.socket.server;

import com.lonni.rpc.core.context.RpcApplicationContext;
import com.lonni.rpc.core.model.RpcConfig;
import com.lonni.rpc.core.socket.SocketUtil;
import com.lonni.rpc.core.socket.codec.RpcProtocolDecoder;
import com.lonni.rpc.core.socket.codec.RpcProtocolEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.net.BindException;
import java.net.InetSocketAddress;
import java.util.concurrent.ThreadFactory;

/**
 * Netty服务端
 *
 * @author: Lonni
 * @date: 2024/7/9 0009 9:30
 */
@Slf4j
public class RpcNettyServer {
    String logBanner = "\n\n" + "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" + "*                                                                                   *\n" + "*                                                                                   *\n" + "*                   {} Server started on  {}.                        *\n" + "*                                                                                   *\n" + "*                                                                                   *\n" + "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n";

    /**
     * 重试次数
     */
    private static int retryCount = 3;
    private static int retryCuurentCount = 1;
    private ServerBootstrap BOOTSTRAP = new ServerBootstrap();
    private EventLoopGroup boosGroup;
    private EventLoopGroup workGroup;
    private ChannelFuture serverFuture;

    private RpcConfig rpcConfig;
    ThreadFactory boosFactory = r -> {
        Thread thread = new Thread(r);
        thread.setName("rpc-netty-boos-");
        return thread;
    };
    ThreadFactory workFactory = r -> {
        Thread thread = new Thread(r);
        thread.setName("rpc-netty-work-");
        return thread;
    };

    public RpcNettyServer(RpcConfig rpcConfig) {
        this.rpcConfig = rpcConfig;

    }

    public void run() {
        int workGroupNum = rpcConfig.getNetty().getWorkGroupNum() == null ? 0 : rpcConfig.getNetty().getWorkGroupNum();
        boosGroup = Epoll.isAvailable() ? new EpollEventLoopGroup(boosFactory) : new NioEventLoopGroup(boosFactory);
        workGroup = Epoll.isAvailable() ? new EpollEventLoopGroup(workGroupNum, workFactory) : new NioEventLoopGroup(workGroupNum, workFactory);
        try {
            BOOTSTRAP = new ServerBootstrap().group(boosGroup, workGroup)
                    //保持链接 保持长连接，2小时无数据激活心跳机制
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    //子处理器处理客户端连接的请求和数据 有数据立即发送
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    //链接超时
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                    //服务端接受连接的队列长度，如果队列已满，客户端连接将被拒绝
                    .option(ChannelOption.SO_BACKLOG, 300)
                    //加入日志处理
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class :
                            NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline()
                                    .addLast(new RpcProtocolEncoder())
                                    .addLast(new RpcProtocolDecoder())
                                    .addLast(new RpcServerHanlder());

                        }
                    });
            serverFuture = BOOTSTRAP.bind(new InetSocketAddress(rpcConfig.getNetty().getPort())).syncUninterruptibly();
            RpcApplicationContext.serverPort=rpcConfig.getNetty().getPort();
            SocketUtil.bindAfterServer(serverFuture, boosGroup, workGroup);
            log.info("rpc server启动完成");
        } catch (Exception ex) {
            log.info("rpc server启动异常", ex);
            if (serverFuture != null) {
                serverFuture.channel().close().addListener(ChannelFutureListener.CLOSE);
                serverFuture.awaitUninterruptibly();
                serverFuture = null;
            }
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
            if (ex instanceof BindException) {
                log.info("端口{}被使用,当前重试次数:{},总重试次数:{}",rpcConfig.getNetty().getPort(),retryCuurentCount,retryCount);
                if (retryCuurentCount >= retryCount) {
                    log.info("Address already in use: bind,超过最大重试次数");
                    throw new IllegalStateException();
                }
                //将端口增加
                rpcConfig.getNetty().setPort(rpcConfig.getNetty().getPort()+1);
                RpcApplicationContext.serverPort=rpcConfig.getNetty().getPort();
                retryCuurentCount++;
                this.run();
            }
        }


    }


}



